/*
 * @Description: 
 * @Author: wangqi
 * @Date: 2021-05-14 23:39:10
 * @LastEditTime: 2021-05-15 16:53:37
 */
import patchVnode from './patchVnode'
import createElement from './createElement'

// 新旧节点是否为同一个节点
function checkSameVnode(oldVnode, newVnode) {
    return oldVnode.sel === newVnode.sel && oldVnode.key === newVnode.key
}

export default function updateChildren(parentElm, oldCh, newCh) {
    /*
        这里设计规则是四种比较规则， 如果在这四种之外的则进入循环匹配
        
        1. 新前 -> 旧前
        2. 新后 -> 旧后
        3. 新后 -> 旧前   （命中后, 新后指向的节点inset到旧后之后）
        4. 新前 -> 旧后   （命中后, 新前指向的节点inset到旧前之前）

        以上四种命中后下标都会移动 (分别设计四个下标);
        只有3,4 命中后节点需要移动
     */

    // 旧前
    let oldStartIdx = 0;
    // 新前
    let newStartIdx = 0;
    // 旧后
    let oldEndIdx = oldCh.length - 1;
    // 新后
    let newEndIdx = newCh.length - 1;

    // 旧前节点
    let oldStartVnode = oldCh[0];
    // 新前节点
    let newStartVnode = newCh[0];
    // 旧后节点
    let oldEndVnode = oldCh[oldEndIdx];
    // 新后节点
    let newEndVnode = newCh[newEndIdx];

    let keyMap = null;

    while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
        // 首先不是判断①②③④命中，而是要略过已经加undefined标记的东西
        if (!oldStartVnode || !oldCh[oldStartIdx]) {
            oldStartVnode = oldCh[++oldStartIdx];
        } else if (!oldEndVnode || !oldCh[oldEndIdx]) {
            oldEndVnode = oldCh[--oldEndIdx];
        } else if (!newStartVnode || !newCh[newStartIdx]) {
            newStartVnode = newCh[++newStartIdx];
        } else if (!newEndVnode || !newCh[newEndIdx]) {
            newEndVnode = newCh[--newEndIdx];

            // 1. 新前 -> 旧前
        } else if (checkSameVnode(oldStartVnode, newStartVnode)) {
            console.log(`1. 新前 -> 旧前 ==`);
            patchVnode(oldStartVnode, newStartVnode);
            oldStartVnode = oldCh[++oldStartIdx];
            newStartVnode = newCh[++newStartIdx];
            // 2. 新后 -> 旧后
        } else if (checkSameVnode(oldEndVnode, newEndVnode)) {
            console.log(`2. 新后 -> 旧后 ==`);
            patchVnode(oldEndVnode, newEndVnode);
            oldEndVnode = oldCh[--oldEndIdx];
            newEndVnode = newCh[--newEndIdx];

            // 3. 新后 -> 旧前 (*注意还需要节点移动位置)
        } else if (checkSameVnode(oldStartVnode, newEndVnode)) {
            console.log(`3. 新后 -> 旧前 ==`);
            patchVnode(oldStartVnode, newEndVnode);
            // 旧前节点 insert到 旧后元素之后的元素
            parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling);
            oldStartVnode = oldCh[++oldStartIdx];
            newEndVnode = newCh[--newEndIdx];

            // 4. 新前 -> 旧后
        } else if (checkSameVnode(oldEndVnode, newStartVnode)) {
            console.log(`4. 新前 -> 旧后  ==`);
            patchVnode(oldEndVnode, newStartVnode);
            parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm);
            oldStartVnode = oldCh[--oldEndIdx];
            newEndVnode = newCh[++newStartIdx];
        } else {
            console.log("都不满足~");
            // 四种命中都没有命中，则用循环处理
            // 四种命中都没有命中
            // 制作keyMap一个映射对象，这样就不用每次都遍历老对象了。
            if (!keyMap) {
                keyMap = {};
                // 从oldStartIdx开始，到oldEndIdx结束，创建keyMap映射对象
                for (let i = oldStartIdx; i <= oldEndIdx; i++) {
                    const key = oldCh[i].key;
                    if (key != undefined) {
                        keyMap[key] = i;
                    }
                }
            }
            console.log(keyMap);
            // 寻找当前这项（newStartIdx）这项在keyMap中的映射的位置序号
            const idxInOld = keyMap[newStartVnode.key];
            console.log(idxInOld);
            if (idxInOld == undefined) {
                // 判断，如果idxInOld是undefined表示它是全新的项
                // 被加入的项（就是newStartVnode这项)现不是真正的DOM节点
                parentElm.insertBefore(createElement(newStartVnode), oldStartVnode.elm);
            } else {
                // 如果不是undefined，不是全新的项，而是要移动
                const elmToMove = oldCh[idxInOld];
                patchVnode(elmToMove, newStartVnode);
                // 把这项设置为undefined，表示我已经处理完这项了
                oldCh[idxInOld] = undefined;
                // 移动，调用insertBefore也可以实现移动。
                parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm);
            }
            // 指针下移，只移动新的头
            newStartVnode = newCh[++newStartIdx];
        }

    }

    // 新增 和 删除
    // 如果旧节点先循环完后,说明新节点有要插入的节点
    // 说明newVnode存在剩余项，需要新增到oldVnode
    if (newStartIdx <= newEndIdx) {
        // const before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm;
        for (let i = newStartIdx; i <= newEndIdx; i++) {
            // console.log(oldCh[oldStartIdx].elm, "xx")
            parentElm.insertBefore(createElement(newCh[i]), oldCh[oldStartIdx].elm);
        }
        // 如果新节点先循环完，说明老节点有剩余节点，是需要被删除的节点
    } else if (oldStartIdx <= oldEndIdx) {
        for (let i = oldStartIdx; i <= oldEndIdx; i++) {
            if (oldCh[i]) {
                parentElm.removeChild(oldCh[i].elm);
            }
        }
    }



}
